package com.bj58.mis.bigdata.demo2.filter;

import java.io.IOException;
import java.util.*;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Order(1)
//@ConditionalOnProperty(name="platform.auth.enable", havingValue="true")
public class AuthFilter implements Filter {


	@Override
	public void init(FilterConfig filterConfig) throws ServletException {

	}

	@Override
	public void doFilter(ServletRequest sevRequest, ServletResponse sevResponse, FilterChain chain)
			throws IOException, ServletException {
		/**
		 * if not a http request then send a error to the client
		 */
		if (sevRequest instanceof HttpServletRequest) {
			HttpServletRequest request = (HttpServletRequest) sevRequest;
			HttpServletResponse response = (HttpServletResponse) sevResponse;

			String path = request.getServletPath();
			System.out.println("[AccessFilter] path = "+path);
			long startTime = System.currentTimeMillis();
			Exception exception = null;
			try{
				chain.doFilter(request, response);
			}catch (IOException ioe){
				exception = ioe;
				throw ioe;
			}catch (ServletException se){
				exception = se;
				throw se;
			}catch (RuntimeException re){
				exception = re;
				throw re;
			}finally {
				long endTime = System.currentTimeMillis();
				accessLog(request, response, (endTime-startTime), exception);

			}
		}
	}

	public void accessLog(HttpServletRequest request, HttpServletResponse response, long elapsedTime, Exception e){
		String path = request.getServletPath();
		Map<String, Object> info = new LinkedHashMap<>();
		info.put("path", path);
		info.put("method", request.getMethod());
		info.put("remoteAddr", request.getRemoteAddr());
		info.put("parameterMap", getParameterMap(request));
		info.put("time", new Date());
		info.put("elapsedTime", elapsedTime);
		info.put("status", response.getStatus());
		info.put("requestHeader", getRequestHeaderMap(request));
		info.put("responseHeader", getResponseHeaderMap(response));
		if(e!=null){
			info.put("exception", e);
		}
		System.out.println("[AccessFilter] ["+request.getMethod()+"] path = "+path+", 耗时: "+elapsedTime+" ms, status="+response.getStatus());
		System.out.println(mapToPrintString(info, ""));
	}

	private String mapToPrintString(Map<String, Object> map, String prefixTab){
		StringBuilder sb = new StringBuilder();
		sb.append("{").append("\n");
		for(String key : map.keySet()){
			Object val = map.get(key);
			sb.append(prefixTab+"\t").append(key).append(" = ");
			if(val instanceof Map){
				sb.append(mapToPrintString((Map<String, Object>)val, prefixTab+"\t"));
			}else{
				sb.append(val).append("\n");
			}
		}
		sb.append(prefixTab).append("}").append("\n");
		return sb.toString();
	}

	private Map<String, Object> getRequestHeaderMap(HttpServletRequest request){
		Map<String, Object> headerMap = new HashMap<>();
		Enumeration<String> headerEnum = request.getHeaderNames();
		while(headerEnum.hasMoreElements()){
			String headerName = headerEnum.nextElement();
			headerMap.put(headerName, request.getHeader(headerName));
		}
		return headerMap;
	}
	private Map<String, Object> getResponseHeaderMap(HttpServletResponse response){
		Map<String, Object> headerMap = new HashMap<>();
		for(String headerName : response.getHeaderNames()){
			headerMap.put(headerName, response.getHeader(headerName));
		}
		return headerMap;
	}
	private Map<String, Object> getParameterMap(HttpServletRequest request){
		Map<String, Object> parameterMap = new HashMap<>();
		for(Map.Entry<String, String[]> entry : request.getParameterMap().entrySet()){
			String[] value = entry.getValue();
			if(value==null || value.length==0){
				parameterMap.put(entry.getKey(), null);
			}else {
				parameterMap.put(entry.getKey(), value[0]);
			}
		}
		return parameterMap;
	}


	@Override
	public void destroy() {
	}


}
